package mk.com.ldm.corepoint.administration.client.presenter;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import mk.com.ldm.corepoint.administration.client.CoreServiceAsync;
import mk.com.ldm.corepoint.administration.client.event.ModalEvent;
import mk.com.ldm.corepoint.administration.shared.ConfigurationObject;
import mk.com.ldm.corepoint.administration.shared.CurrentObject;
import mk.com.ldm.corepoint.administration.shared.DataBaseObject;
import mk.com.ldm.corepoint.administration.shared.EventObject;
import mk.com.ldm.corepoint.administration.shared.Foreign;
import mk.com.ldm.corepoint.administration.shared.PermissionsObject;
import mk.com.ldm.corepoint.administration.shared.TableData;
import mk.com.ldm.corepoint.administration.shared.TemporaryStorage;

import org.gwt.mosaic.core.client.Dimension;
import org.gwt.mosaic.ui.client.MessageBox;
import org.gwt.mosaic.ui.client.WindowPanel;

import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.PasswordTextBox;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;

public class EditPresenter implements Presenter {
	
	private CoreServiceAsync rpcService;
	private HandlerManager eventBus;
	private Display display;

	private ArrayList<ConfigurationObject> config = new ArrayList<ConfigurationObject>();
	private ArrayList<ArrayList<EventObject>> eventsList = new ArrayList<ArrayList<EventObject>>();
	private ArrayList<Boolean> includeInSimple = new ArrayList<Boolean>();
		
	public interface Display{
		Button getCreateButton();
		Button getCancelButton();
		Button getAddPageButton();
		Button getAddEventButton();
		Button getAddForeignButton();
		Button getPageNameButton();
		Button getSaveButton();
		Button getAddUserButton();
		Button getAddPermissionButton();
		Button getAppSettingsButton();
		TextBox getNameTextBox();
		TextBox getPageNameTextBox();
		WindowPanel getModalWindow();
		ArrayList<Widget> getPageWidgets();
		ArrayList<Widget> getEventWidgets();
		ArrayList<Widget> getForeignWidgets();
		ArrayList<Widget> getUserWidgets();
		ArrayList<Widget> getPermissionsWidgets();
		ArrayList<Widget> getRolesPermissionsWidgets();
		ArrayList<Widget> getAppSettingsWidgets();
		void setObject(String name);
		Widget asWidget();
	}

	public EditPresenter(CoreServiceAsync rpcService, HandlerManager eventBus, Display view) {
	    this.rpcService = rpcService;
	    this.eventBus = eventBus;
	    this.display = view;

	}
	
	public void bind(){
		
		display.getCancelButton().addClickHandler(new ClickHandler(){

			@Override
			public void onClick(ClickEvent event) {
				display.getModalWindow().hide();
			}
			
		});
		
		if(display.getPageWidgets() != null){
			Button formOpenEventMapper = (Button)display.getPageWidgets().get(35);
			formOpenEventMapper.addClickHandler(new ClickHandler(){

				@Override
				public void onClick(ClickEvent event) {
					eventBus.fireEvent(new ModalEvent("new","events"));
				}
				
			});
			
			final Button formOpenForeignRelations = (Button)display.getPageWidgets().get(15);
			formOpenForeignRelations.setEnabled(false);
			formOpenForeignRelations.addClickHandler(new ClickHandler(){

				@Override
				public void onClick(ClickEvent event) {
					eventBus.fireEvent(new ModalEvent("new","foreign keys"));
				}
				
			});
			
			CheckBox formEnabledCheckBox = (CheckBox)display.getPageWidgets().get(11);
			formEnabledCheckBox.setValue(true);
			
			final CheckBox formForeignCheckBox = (CheckBox)display.getPageWidgets().get(13);
			formForeignCheckBox.addClickHandler(new ClickHandler(){

				@Override
				public void onClick(ClickEvent event) {
					if(formForeignCheckBox.getValue() == true){
						formOpenForeignRelations.setEnabled(true);
					} else {
						formOpenForeignRelations.setEnabled(false);
					}
					
				}
				
			});
		}
		
		if(display.getUserWidgets() != null){
			Button permissionsEventMapper = (Button)display.getUserWidgets().get(7);
			
			permissionsEventMapper.addClickHandler(new ClickHandler(){
				@Override
				public void onClick(ClickEvent event) {
					eventBus.fireEvent(new ModalEvent("new","permission"));
				}
			});
			fillRolesList((ListBox)display.getUserWidgets().get(5));
		}
		
		if(display.getRolesPermissionsWidgets() != null){
			final ListBox rolesList = (ListBox)display.getRolesPermissionsWidgets().get(0);
			fillRolesList(rolesList);
			ListBox addRolesList = (ListBox)display.getRolesPermissionsWidgets().get(3);
			addRolesList.addItem("None", "none");
			fillRolesList(addRolesList);
			final FlexTable permissionsTable = (FlexTable)display.getRolesPermissionsWidgets().get(1);
			rolesList.addChangeHandler(new ChangeHandler() {
				@Override
				public void onChange(ChangeEvent event) {
					fillPermissionsTable(permissionsTable, rolesList.getValue(rolesList.getSelectedIndex()));
				}
			});
			fillPermissionsTable(permissionsTable, "1");
		}
		
		if(display.getAppSettingsWidgets() != null){
			
		}
		
		display.getCreateButton().addClickHandler(new ClickHandler(){

			@Override
			public void onClick(ClickEvent event) {
				createProject(display.getNameTextBox().getValue());
				display.getModalWindow().hide();
			}
			
		});
		
		if(display.getAddPageButton() != null){
			final Button addPageButton = display.getAddPageButton();
			addPageButton.addClickHandler(new ClickHandler(){

				@Override
				public void onClick(ClickEvent event) {
					
						TextBox parametersBox = (TextBox)display.getPageWidgets().get(1);
						String parameters = parametersBox.getValue();
						
						TextBox formNameBox = (TextBox)display.getPageWidgets().get(3);
						String formName = formNameBox.getValue();
						
						TextBox dbNameBox = (TextBox)display.getPageWidgets().get(5);
						String dbName = dbNameBox.getValue(); 
						
						ListBox formTypeBox = (ListBox)display.getPageWidgets().get(7);
						String formType = formTypeBox.getValue(formTypeBox.getSelectedIndex());
						
						CheckBox enabledBox = (CheckBox)display.getPageWidgets().get(11);
						Boolean enabled = enabledBox.getValue();
						
						CheckBox foreignBox = (CheckBox)display.getPageWidgets().get(13);
						Boolean foreign = foreignBox.getValue();
						
						CheckBox filterBox = (CheckBox)display.getPageWidgets().get(17);
						Boolean filter = filterBox.getValue();
						
						TextBox valueBox = (TextBox)display.getPageWidgets().get(19);
						String value = valueBox.getValue();
						
						ListBox dbTypeBox = (ListBox)display.getPageWidgets().get(21);
						String dbType = dbTypeBox.getValue(dbTypeBox.getSelectedIndex());
						
						TextBox dbSizeBox = (TextBox)display.getPageWidgets().get(23);
						if(dbSizeBox.getValue() != null && !dbSizeBox.getValue().equals("") ){
							dbType += "("+dbSizeBox.getValue()+")";
						}
						
						ListBox validationTypeBox = (ListBox)display.getPageWidgets().get(25);
						String validationType = validationTypeBox.getValue(validationTypeBox.getSelectedIndex());
						
						TextBox weightBox = (TextBox)display.getPageWidgets().get(27);
						Integer formWeight = Integer.parseInt(weightBox.getValue());
						
						CheckBox visibleBox = (CheckBox)display.getPageWidgets().get(29);
						Boolean visible = visibleBox.getValue();
						
						TextBox colBox = (TextBox)display.getPageWidgets().get(31);
						Integer col = Integer.parseInt(colBox.getValue());
						
						TextBox rowBox = (TextBox)display.getPageWidgets().get(33);
						Integer row = Integer.parseInt(rowBox.getValue());
						
						ConfigurationObject configurationObject = new ConfigurationObject(parameters, formName, dbName, formType, enabled, filter, value, dbType, validationType, formWeight, visible, col, row, CurrentObject.getInstance().getEvents());
						if(CurrentObject.getInstance().getForeign() != null){
							configurationObject.setForeign(TemporaryStorage.getInstance().getForeign());
						}
						
						CheckBox simpleBox = (CheckBox)display.getPageWidgets().get(37);
						Boolean isSimple = simpleBox.getValue();
						CurrentObject.getInstance().setIsSimple(isSimple);
						includeInSimple.add(isSimple);
						
						CurrentObject.getInstance().setConfig(configurationObject);
						
						for(EventObject e:configurationObject.getEvents()){
							e.setId(formName);
						}
						
						addObject();
						display.setObject(formName);
				}
				
			});
		}
		if(display.getAddEventButton() != null){
			final Button addEventButton = display.getAddEventButton();
			addEventButton.addClickHandler(new ClickHandler(){

				@Override
				public void onClick(ClickEvent event) {
						EventObject eventObject = new EventObject();
						ListBox name = (ListBox)display.getEventWidgets().get(1);
						ListBox fires = (ListBox)display.getEventWidgets().get(3);
						
						eventObject.setType(name.getValue(name.getSelectedIndex()));
						eventObject.setFires(fires.getValue(fires.getSelectedIndex()));
						
						CurrentObject.getInstance().setEvent(eventObject);
						display.getModalWindow().hide();
				}
				
			});
		}
		if(display.getAddForeignButton() != null){
			final Button addForeignButton = display.getAddForeignButton();
			addForeignButton.addClickHandler(new ClickHandler(){

				@Override
				public void onClick(ClickEvent event) {
						TextBox tableName = (TextBox)display.getForeignWidgets().get(1);
						TextBox fieldName = (TextBox)display.getForeignWidgets().get(3);
						TextBox idName = (TextBox)display.getForeignWidgets().get(5);
						
						CurrentObject.getInstance().getForeign().setIsForeign(true);
						CurrentObject.getInstance().getForeign().setTableName(tableName.getValue());
						CurrentObject.getInstance().getForeign().setIdColumnName(idName.getValue());
						CurrentObject.getInstance().getForeign().setColumnName(fieldName.getValue());
						
						TemporaryStorage.getInstance().addForeign(CurrentObject.getInstance().getForeign());						
						
						display.getModalWindow().hide();
				}
				
			});
		}
		
		if(display.getPageNameButton() != null){
			final Button setPageNameButton = display.getPageNameButton();
			setPageNameButton.addClickHandler(new ClickHandler(){

				@Override
				public void onClick(ClickEvent event) {
					config.clear();
					CurrentObject.getInstance().setObjectName(display.getPageNameTextBox().getValue());
					eventBus.fireEvent(new ModalEvent("new","page"));
					display.getModalWindow().hide();
					includeInSimple.clear();
				}
				
			});
		}
		
		if(display.getAddUserButton() != null){
			final Button addUserButton = display.getAddUserButton();
			addUserButton.addClickHandler(new ClickHandler(){

				@Override
				public void onClick(ClickEvent event) {
					TextBox userNameBox = (TextBox)display.getUserWidgets().get(1);
					String userName = userNameBox.getValue();
					PasswordTextBox passwordBox = (PasswordTextBox)display.getUserWidgets().get(3);
					String password = passwordBox.getValue();
					ListBox roleBox = (ListBox)display.getUserWidgets().get(5);
					String role = roleBox.getValue(roleBox.getSelectedIndex());
					
					CurrentObject.getInstance().getUser().setUsername(userName);
					CurrentObject.getInstance().getUser().setPassword(password);
					CurrentObject.getInstance().getUser().setRole(role);
					CurrentObject.getInstance().getUser().setPermissions(CurrentObject.getInstance().getPermissions());
					
					
					doSaveUser();			
					display.getModalWindow().hide();
				}
				
			});
			
			Button addEditPermissions = (Button)display.getUserWidgets().get(8);
			addEditPermissions.addClickHandler(new ClickHandler() {
				
				@Override
				public void onClick(ClickEvent event) {
					eventBus.fireEvent(new ModalEvent("edit", "permissions"));
				}
			});
		}
		
		if(display.getAddPermissionButton() != null){
			final Button addPermissionsButton = display.getAddPermissionButton();
			
			addPermissionsButton.addClickHandler(new ClickHandler(){

				@SuppressWarnings("deprecation")
				@Override
				public void onClick(ClickEvent event) {
					ListBox pageBox = (ListBox)display.getPermissionsWidgets().get(1);
					String page = pageBox.getValue(pageBox.getSelectedIndex());
					RadioButton typeBox = (RadioButton)display.getPermissionsWidgets().get(4);
					String type = new String();
					if(typeBox.isChecked()) type = "allowed";
					else type="forbidden";
					TextArea valuesArea = (TextArea)display.getPermissionsWidgets().get(8);
					String[] valuesString = valuesArea.getValue().split(",");
					
					ArrayList<String> values = new ArrayList<String>();
					for(int i=valuesString.length - 1; i>=0; i--){
						valuesString[i] = valuesString[i].trim();
						values.add(valuesString[i]);
					}
					
					
					PermissionsObject permissionsObject = new PermissionsObject();
					
					permissionsObject.setPermissionType(type);
					permissionsObject.setViewName(page);
					permissionsObject.setValues(values);
					
					CurrentObject.getInstance().setPermissions(permissionsObject);
					
					display.getModalWindow().hide();
					
				}
				
			});
		}
		
		display.getAppSettingsButton().addClickHandler(new ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				ArrayList<String> settings = new ArrayList<String>();
				for(int i=0; i<display.getAppSettingsWidgets().size()-1; i++){
					settings.add(((TextBox)display.getAppSettingsWidgets().get(i)).getValue());
				}
				settings.add(((TextArea)display.getAppSettingsWidgets().get(7)).getValue());
				rpcService.generateApplicationMap(settings, new AsyncCallback<Boolean>() {
					
					@Override
					public void onSuccess(Boolean result) {
						if(result)
							MessageBox.info("Info", "Settings saved successfully.");
						else
							MessageBox.error("Error", "Settings could not be saved.");
					}
					
					@Override
					public void onFailure(Throwable caught) {
						MessageBox.error("Error", "Settings could not be saved.");
					}
				});
			}
		});
		
		display.getSaveButton().addClickHandler(new ClickHandler(){
				
				public void onClick(ClickEvent event) {
					doSaveObject();
				}
				
		});
	}
	
	public void go(final HasWidgets container) {
		bind();
	}
	
	private void fillRolesList(final ListBox list){
		ArrayList<DataBaseObject> columns = new ArrayList<DataBaseObject>();
		DataBaseObject uid = new DataBaseObject("u_id", false);
		DataBaseObject uname = new DataBaseObject("u_name", true);
		DataBaseObject upid = new DataBaseObject("u_pid", false, true, "0");
		columns.add(uid);
		columns.add(uname);
		columns.add(upid);
		
		rpcService.getKeyValuePairFromTable("users", columns, new AsyncCallback<Map<String,String>>() {
			
			@Override
			public void onSuccess(Map<String, String> result) {
				Set<String> keys = result.keySet();
				for(Iterator<String> i = keys.iterator(); i.hasNext();){
					String id = i.next();
					String val = result.get(id);
					list.addItem(val, id);
				}
			}
			
			@Override
			public void onFailure(Throwable caught) {
				MessageBox.error("FAIL", "Failed getting user roles<br />"+caught.getMessage());
			}
		});
	}
	
	private void fillPermissionsTable(final FlexTable table, String id){
		ArrayList<Foreign> foreign = new ArrayList<Foreign>();
		Foreign f = new Foreign("pages", "p_name", "p_id", false);
		foreign.add(f);
		ArrayList<DataBaseObject> columns = new ArrayList<DataBaseObject>();
		DataBaseObject view = new DataBaseObject("p_view", false);
		DataBaseObject add = new DataBaseObject("p_add", false);
		DataBaseObject edit = new DataBaseObject("p_edit", false);
		DataBaseObject delete = new DataBaseObject("p_delete", false);
		DataBaseObject page = new DataBaseObject("page_id", false, foreign);
		DataBaseObject where = new DataBaseObject("u_id", false, true, id);
		columns.add(view);
		columns.add(add);
		columns.add(edit);
		columns.add(delete);
		columns.add(page);
		columns.add(where);
		
		table.setWidget(0, 0, new Label(""));
		table.setWidget(0, 1, new Label("View"));
		table.setWidget(0, 2, new Label("Add"));
		table.setWidget(0, 3, new Label("Edit"));
		table.setWidget(0, 4, new Label("Delete"));
		
		rpcService.getTableData("permissions", columns, false, new AsyncCallback<ArrayList<TableData>>() {
			
			@Override
			public void onSuccess(ArrayList<TableData> result) {
				for(int i=0; i<result.size(); i++){
					table.setWidget(i+1, 0, new Label(result.get(i).getTableData().get(5)));
					CheckBox cb1 = new CheckBox(), cb2 = new CheckBox(), cb3 = new CheckBox(), cb4 = new CheckBox();
					if(result.get(i).getTableData().get(0).equals("t"))
						cb1.setValue(true);
					if(result.get(i).getTableData().get(1).equals("t"))
						cb2.setValue(true);
					if(result.get(i).getTableData().get(2).equals("t"))
						cb3.setValue(true);
					if(result.get(i).getTableData().get(3).equals("t"))
						cb4.setValue(true);
					cb1.setName(result.get(i).getTableData().get(4));
					cb2.setName(result.get(i).getTableData().get(4));
					cb3.setName(result.get(i).getTableData().get(4));
					cb4.setName(result.get(i).getTableData().get(4));
					table.setWidget(i+1, 1, cb1);
					table.setWidget(i+1, 2, cb2);
					table.setWidget(i+1, 3, cb3);
					table.setWidget(i+1, 4, cb4);
				}
//				MessageBox.info("", display.getModalWindow().getWidget().toString());
//				
//				display.getModalWindow().setHeight(display.getModalWindow().getWidget().getOffsetHeight()+"px");
//				display.getModalWindow().setWidth(display.getModalWindow().getWidget().getOffsetWidth()+"px");
				//display.getModalWindow().setHeight(display.getModalWindow().getContentWidth()+"px");
//				display.getModalWindow().setHeight((display.getModalWindow().getContentHeight()+table.getOffsetHeight())+"px");
//				display.getModalWindow().setWidth("500px");
				display.getModalWindow().setPixelSize(500, display.getModalWindow().getContentHeight()+table.getOffsetHeight());
				
				display.getModalWindow().getWidget().setHeight(display.getModalWindow().getContentHeight()+"px");
				display.getModalWindow().getWidget().setWidth("500px");
				display.getModalWindow().center();
			}
			
			@Override
			public void onFailure(Throwable caught) {
				// TODO Auto-generated method stub
				
			}
		});
	}
	
	public void createProject(String name){
		final String _name = name;
		rpcService.createProject(name, new AsyncCallback<Boolean>(){

			@Override
			public void onFailure(Throwable caught) {
				MessageBox.error("Server", "Failed to communicate with the server");
			}

			@Override
			public void onSuccess(Boolean result) {
				if(result == true){
					MessageBox.info("Server", "Project succesfully created.");
					TemporaryStorage.getInstance().setSelectedProject(_name);
					History.newItem("main");
					History.fireCurrentHistoryState();
				}
				else MessageBox.error("Server", "There was an error creating the project. Please try again.");
			}
			
		});
		
	}
	
	public void addObject(){
		
		String msg = new String();
		
		if(CurrentObject.getInstance().getConfig() != null){
			config.add(CurrentObject.getInstance().getConfig());
		} else {
			msg += "Object is empty. Please fill all required fields. <br/>";
		}
		
		if(CurrentObject.getInstance().getEvents() != null){
			eventsList.add(CurrentObject.getInstance().getEvents());
		} else {
			eventsList.add(new ArrayList<EventObject>());
			msg += "No events specified for this object.";
		}
		
		if(!msg.isEmpty()){
			MessageBox.alert("Warning",msg);
		}
		
	}
	
	public void doSaveObject(){
		rpcService.generateConfigurationMap(CurrentObject.getInstance().getObjectName(), "", config, includeInSimple,  new AsyncCallback<Boolean>() {
			@Override
			public void onSuccess(Boolean result) {
				if(result)
					MessageBox.info("Server", "Object saved.");
				else
					MessageBox.error("Server", "Error during object save. Please try again.");
				config.clear();
			}
			
			@Override
			public void onFailure(Throwable caught) {
				MessageBox.error("Server", "Failed to communicate with the server");
				config.clear();
			}
		});
	}

	public void doSaveUser(){
		rpcService.generateUserAndPermissionsMap(CurrentObject.getInstance().getUser(), new AsyncCallback<Boolean>(){

			@Override
			public void onFailure(Throwable caught) {
				MessageBox.error("Server", "Failed to communicate with the server");
			}

			@Override
			public void onSuccess(Boolean result) {
				if(result)
					MessageBox.info("Server", "User saved.");
				else
					MessageBox.error("Server", "Error during user save. Please try again.");
			}
			
		});
	}
	
}
